package com.sparrow.common.object;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.function.Supplier;

/**
 * 对象池
 *
 * @param <T> 对象类型，需要实现 Resettable 接口
 */
public class ObjectPool<T extends Resettable> {
    private Logger logger = LoggerFactory.getLogger(ObjectPool.class);

    private final Deque<T> pool = new ArrayDeque<>();
    private final Set<T> inPoolSet =
            Collections.newSetFromMap(new IdentityHashMap<>());    private final Supplier<T> creator;
    private final int maxSize;
    private final boolean debug;

    /**
     * 构造对象池
     *
     * @param creator  对象创建函数
     * @param initSize 初始预填充数量
     * @param maxSize  池最大容量
     * @param debug    是否开启调试日志
     */
    public ObjectPool(Supplier<T> creator, int initSize, int maxSize, boolean debug) {
        if (initSize > maxSize) {
            throw new IllegalArgumentException("initSize cannot be greater than maxSize");
        }
        this.creator = creator;
        this.maxSize = maxSize;
        this.debug = debug;
        prefill(initSize);
    }

    /**
     * 获取对象，如果池为空则创建新对象
     */
    public T get() {
        T obj = pool.pollFirst();
        if (obj != null) {
            inPoolSet.remove(obj);
            if (debug) {
                logger.info("ObjectPool: 获取空闲对象 {}", obj);
            }
            return obj;
        }
        if (debug) {
            logger.info("ObjectPool: 创建新对象");
        }
        return creator.get();
    }

    /**
     * 回收对象到池中
     * 自动调用 reset() 并防止重复回收
     */
    public void recycle(T obj) {
        if (obj == null) return;
        // 已经在池里（基于 == 判断）
        if (!inPoolSet.add(obj)) {
            if (debug) {
                logger.info("ObjectPool: 重复回收对象 {} identity{}", obj, System.identityHashCode(obj));
            }
            return;
        } else {
            if (debug) {
                logger.info("ObjectPool: 回收对象 {} identity{}", obj, System.identityHashCode(obj));
            }
        }

        if (pool.size() >= maxSize) {
            inPoolSet.remove(obj); // 保持一致
            if (debug) {
                logger.info("ObjectPool: 超过最大容量，丢弃对象 {}", obj);
            }
            return;
        }

        obj.reset(); // ✅ 在确定放回池子时才 reset
        pool.offerFirst(obj);

        if (debug) {
            logger.info("ObjectPool: 回收对象 {}", obj);
        }
    }


    /**
     * 清空对象池
     */
    public void clear() {
        pool.clear();
        inPoolSet.clear();
    }

    /**
     * 池中对象数量
     */
    public int size() {
        return pool.size();
    }

    /**
     * 预填充对象池
     *
     * @param n 预填充数量
     */
    public void prefill(int n) {
        for (int i = 0; i < n && pool.size() < maxSize; i++) {
            T obj = creator.get();
            if (inPoolSet.add(obj)) {
                pool.offerFirst(obj);
            }
        }
    }
}
